@file:OptIn(ExperimentalUuidApi::class)

package com.harth.blemultiplatform.ble

import com.harth.blemultiplatform.ble.core.CharacteristicProperty
import com.harth.blemultiplatform.ble.core.WriteType
import kotlinx.coroutines.flow.Flow
import kotlin.uuid.ExperimentalUuidApi
import kotlin.uuid.Uuid

interface ICharacteristic{

    val uuid: Uuid
    val service: IService
    val peripheral: IPeripheral
        get() = service.peripheral

    val descriptors:List<IDescriptor>

    val properties: List<CharacteristicProperty>


    /**
     * Returns whether the characteristic is notifying or indicating.
     */
    val isNotifying: Boolean

    /**
     * Sets notifications or indications state, depending on the characteristic's properties.
     *
     * Note, that calling [suspend] or [waitForValueChange] will enable notifications
     * automatically.
     *
     * @throws OperationFailedException if the operation failed.
     * @throws InvalidAttributeException if the characteristic has been invalidated due to
     * disconnection of service change event.
     * @throws BluetoothException if the implementation fails, see cause for a reason.
     */
    suspend fun setNotifying(enabled: Boolean)

    /**
     * Reads the value of the characteristic.
     *
     * @return The value of the characteristic.
     * @throws OperationFailedException if the operation failed.
     * @throws InvalidAttributeException if the characteristic has been invalidated due to
     * disconnection of service change event.
     * @throws BluetoothException if the implementation fails, see cause for a reason.
     */
    suspend fun read(): ByteArray

    /**
     * Writes the value of the characteristic.
     *
     * @param data The data to be written.
     * @param writeType The write type to be used.
     * @throws OperationFailedException if the operation failed.
     * @throws InvalidAttributeException if the characteristic has been invalidated due to
     * disconnection of service change event.
     * @throws BluetoothException if the implementation fails, see cause for a reason.
     */
    suspend fun write(data: ByteArray, writeType: WriteType)

    /**
     * Subscribes for notifications or indications of the characteristic.
     *
     * This method suspends until the notifications are enabled.
     *
     * The client will NOT unsubscribe when the flow is closed.
     * Use [setNotifying] to disable notifications or indications.
     *
     * @throws OperationFailedException if the operation failed.
     * @throws InvalidAttributeException if the characteristic has been invalidated due to
     * disconnection of service change event.
     * @throws BluetoothException if the implementation fails, see cause for a reason.
     * @see isNotifying
     * @see setNotifying
     */
    suspend fun subscribe(): Flow<ByteArray>

    /**
     * Waits for the value of the characteristic to change.
     *
     * This method suspends until the value of the characteristic changes.
     * If the notifications are not enabled, it will enable them automatically.
     * Use [setNotifying] to disable notifications or indications.
     *
     * @return The new value of the characteristic.
     * @throws OperationFailedException if the operation failed.
     * @throws InvalidAttributeException if the characteristic has been invalidated due to
     * disconnection of service change event.
     * @throws BluetoothException if the implementation fails, see cause for a reason.
     * @see subscribe
     * @see isNotifying
     * @see setNotifying
     */
    suspend fun waitForValueChange(): ByteArray
}